package detect;

import interfaces.Detect;

import java.net.InetAddress;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import models.DS_IPRangeModel;
import models.JavaCommandLineServiceAccounts;
import util.ExecCmdHandle;
import util.Utils;
import entities.Domain;
import entities.IPRange;

public class DetectDomainWhoisInfor implements Detect {

	public static Pattern p;
	public static Matcher m;

	@Override
	public void getInfo(Map<String, Object> obj) {
		Domain d = (Domain) obj.get("domain");
		// Process dig cmd to domain name to get email, server ip.
		String cmdLine = "dig +nocmd " + d.getName() + " ANY +noall +answer";
		String digResult = ExecCmdHandle.processCommand(cmdLine);
		if (digResult != null && digResult.length() > 0) {
			d.setDig(digResult);
		}
		processServerIP(d);
		processServerEmail(d);
		processWhoisDomain(d);
		processWhoisIPAddress(d);
	}

	public static void processServerIP(Domain d) {
		boolean catcha = false;
		String serverIP = "";

		if (d.getDig().length() > 0) {
			// Get IP Line from list dig answer
			String[] tempSplitArr = d.getDig().split("\\n|\\r");
			List<String[]> tempList = new ArrayList<String[]>();
			for (String tempStr : tempSplitArr) {
				String[] temp = tempStr.trim().split("\\s+");
				tempList.add(temp);
			}
			for (String[] strings : tempList) {
				if (strings.length == 5) {
					String recordType = strings[3];
					String recordValue = strings[4];
					if (recordType.equals("A")
							&& Utils.isIPAddress(recordValue)) {
						serverIP = recordValue;
						catcha = true;
						break;
					}
				}
			}
		}

		// Try get IP with InetAddress
		if (!catcha) {
			try {
				InetAddress address = InetAddress.getByName(new URL("http://"
						+ d.getName()).getHost());
				if (Utils.isIPAddress(address.getHostAddress())) {
					catcha = true;
					serverIP = address.getHostAddress();
				}
			} catch (Exception e) {
				e.printStackTrace();			
				catcha = false;
				serverIP = "";				
			}
		}

		// If dig result have no A, redo cmd with type = A
		if (!catcha) {
			String tempDig = ExecCmdHandle.processCommand("dig " + d.getName()
					+ " A +short");
			for (String strings : tempDig.split("\\n|\\r")) {
				if (Utils.isIPAddress(strings)) {
					serverIP = strings;
					catcha = true;
					break;
				}
			}
		}
		if (catcha) {
			d.setIp(serverIP);
		}
	}

	public static void processServerEmail(Domain d) {
		boolean catcha = false;
		String serverEmail = "";
		String email = "";

		// Get MX Record from list answer
		if (d.getDig().length() > 0) {
			String[] tempSplitArr = d.getDig().split("\\n|\\r");
			List<String[]> tempList = new ArrayList<String[]>();
			for (String tempStr : tempSplitArr) {
				String[] temp = tempStr.trim().split("\\s+");
				tempList.add(temp);
			}
			for (String[] strings : tempList) {
				if (strings.length >= 5) {
					String recordType = "";
					String recordValue = "";
					for (int i = 3; i < strings.length; i++) {
						if (i == 3) {
							recordType = strings[i];
						} else if (i == 4) {
							recordValue = strings[i];
						} else {
							recordValue += " " + strings[i];
						}
					}
					if (recordType.contains("MX")) {
						catcha = true;
						if (Utils.isEmail(recordValue)) {
							email += recordValue + ", ";
						} else {
							serverEmail += recordValue + ", ";
						}
					}
				}
			}
		}

		// If dig result have no MX, redo cmd with type = MX
		if (!catcha) {
			String tempStr = ExecCmdHandle.processCommand("dig " + d.getName()
					+ " MX +short");
			for (String strings : tempStr.split("\\n|\\r")) {
				if (Utils.isEmail(strings)) {
					email += strings + ", ";
				} else {
					serverEmail += strings + ", ";
				}
			}
		}

		// Handle server email and email to save
		if (serverEmail.length() > 0) {
			serverEmail = serverEmail.trim();
			if (serverEmail.endsWith(",")) {
				serverEmail = serverEmail
						.substring(0, serverEmail.length() - 1);
			}
			d.setServerEmail(serverEmail);
		}
		if (email.length() > 0) {
			email = email.trim();
			if (email.endsWith(",")) {
				email = email.substring(0, email.length() - 1);
			}
			if (d.getEmail().length() > 0) {
				d.setEmail(d.getEmail() + ", " + email);
			} else {
				d.setEmail(email);
			}
		}
	}

	public static void processWhoisDomain(Domain d) {
		if (d.getName().contains(".vn")) {
			processWhoisDomain_dot_VN(d);
		} else if (d.getName().contains(".ru")) {
			processWhoisDomain_dot_RU(d);
		} else if (d.getName().contains(".jp")) {
			processWhoisDomain_dot_JP(d);
		} else if (d.getName().contains(".cn")) {
			processWhoisDomain_dot_CN(d);
		} else {
			processWhoisDomain_dot_DEFAULT(d);
		}
	}

	public static void processWhoisDomain_dot_VN(Domain d) {
		String whoisDomainResult = Utils.getDotVnWhois(d.getName());
		if (whoisDomainResult != null && whoisDomainResult.length() > 0) {
			d.setWhois(whoisDomainResult);
		}
		String createdDate = valueOfField("Issue Date", 1, d.getWhois());
		String expiredDate = valueOfField("Expired Date", 1, d.getWhois());
		String updatedDate = valueOfField("Updated Date", 1, d.getWhois());
		String emailString = valueOfField("Tech Email", 0, d.getWhois());
		if (emailString.length() > 0) {
			if (d.getEmail().length() > 0) {
				d.setEmail(d.getEmail() + ", " + emailString);
			} else {
				d.setEmail(emailString);
			}
		}
		d.setExpiredDate(expiredDate);
		d.setCreatedDate(createdDate);
		d.setUpdatedDate(updatedDate);
		d.setNameServer(valueOfField("DNS", 0, d.getWhois()));
		d.setDomainStatus(valueOfField("Status", 0, d.getWhois()));
	}

	public static void processWhoisDomain_dot_RU(Domain d) {
		// Domain .ru date format example 2014.08.01
		String whoisDomainResult = ExecCmdHandle.processCommand("whois "
				+ d.getName());
		if (whoisDomainResult != null && whoisDomainResult.length() > 0) {
			d.setWhois(whoisDomainResult);
		}
		String createdDate = valueOfField("created", 1, d.getWhois()).trim();
		String expiredDate = valueOfField("paid-till", 1, d.getWhois()).trim();
		String domainStatus = valueOfField("state", 0, d.getWhois()).trim();
		String nameServer = valueOfField("nserver", 0, d.getWhois());

		Calendar cal = Calendar.getInstance();
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd");
		try {
			cal.setTime(dateFormat.parse(createdDate));
			createdDate = String.format("%02d", cal.get(Calendar.MONTH) + 1)
					+ "/" + String.format("%02d", cal.get(Calendar.DATE)) + "/"
					+ cal.get(Calendar.YEAR);
		} catch (ParseException e) {
		}
		try {
			cal.setTime(dateFormat.parse(expiredDate));
			expiredDate = String.format("%02d", cal.get(Calendar.MONTH) + 1)
					+ "/" + String.format("%02d", cal.get(Calendar.DATE)) + "/"
					+ cal.get(Calendar.YEAR);
		} catch (ParseException e) {
		}

		d.setExpiredDate(expiredDate);
		d.setCreatedDate(createdDate);
		d.setDomainStatus(domainStatus);
		d.setNameServer(nameServer);
	}

	public static void processWhoisDomain_dot_JP(Domain d) {
		// Domain .ru date format example 2014.08.01
		String whoisDomainResult = ExecCmdHandle.processCommand("whois "
				+ d.getName());
		if (whoisDomainResult != null && whoisDomainResult.length() > 0) {
			d.setWhois(whoisDomainResult);
		}		
		String createdDate = valueOfJapaneseWhoisField("Registered Date", 1,
				d.getWhois()).trim();
		if (createdDate.length() == 0 || createdDate.equals("")) {
			createdDate = valueOfJapaneseWhoisField("Created on", 1,
					d.getWhois()).trim();
		}
		String expiredDate = valueOfJapaneseWhoisField("Expired Date", 1,
				d.getWhois()).trim();
		if (expiredDate.length() == 0 || expiredDate.equals("")) {
			expiredDate = valueOfJapaneseWhoisField("Expires on", 1,
					d.getWhois()).trim();
		}
		String updatedDate = valueOfJapaneseWhoisField("Last Update", 1,
				d.getWhois()).trim();
		if (updatedDate.length() == 0 || updatedDate.equals("")) {
			updatedDate = valueOfJapaneseWhoisField("Last Updated", 1,
					d.getWhois()).trim();
		}
		String domainStatus = valueOfJapaneseWhoisField("State", 0,
				d.getWhois()).trim();
		if (domainStatus.length() == 0 || domainStatus.equals("")) {
			domainStatus = valueOfJapaneseWhoisField("Status", 1, d.getWhois())
					.trim();
		}
		String nameServer = valueOfJapaneseWhoisField("Name Server", 0,
				d.getWhois());

		Calendar cal = Calendar.getInstance();
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
		try {
			cal.setTime(dateFormat.parse(createdDate));
			createdDate = String.format("%02d", cal.get(Calendar.MONTH) + 1)
					+ "/" + String.format("%02d", cal.get(Calendar.DATE)) + "/"
					+ cal.get(Calendar.YEAR);
		} catch (ParseException e) {
		}
		try {
			cal.setTime(dateFormat.parse(updatedDate));
			updatedDate = String.format("%02d", cal.get(Calendar.MONTH) + 1)
					+ "/" + String.format("%02d", cal.get(Calendar.DATE)) + "/"
					+ cal.get(Calendar.YEAR);
		} catch (ParseException e) {
		}
		try {
			cal.setTime(dateFormat.parse(expiredDate));
			expiredDate = String.format("%02d", cal.get(Calendar.MONTH) + 1)
					+ "/" + String.format("%02d", cal.get(Calendar.DATE)) + "/"
					+ cal.get(Calendar.YEAR);
		} catch (ParseException e) {
		}

		d.setExpiredDate(expiredDate);
		d.setCreatedDate(createdDate);
		d.setUpdatedDate(updatedDate);
		d.setDomainStatus(domainStatus);
		d.setNameServer(nameServer);
	}

	public static void processWhoisDomain_dot_CN(Domain d) {
		// Domain .ru date format example 2014.08.01
		String whoisDomainResult = ExecCmdHandle.processCommand("whois "
				+ d.getName());
		if (whoisDomainResult != null && whoisDomainResult.length() > 0) {
			d.setWhois(whoisDomainResult);
		}
		String createdDate = valueOfField("Registration Date", 1, d.getWhois())
				.trim();
		String expiredDate = valueOfField("Expiration Date", 1, d.getWhois())
				.trim();
		String updatedDate = valueOfField("Update Date", 1, d.getWhois())
				.trim();
		String domainStatus = valueOfField("Domain Status", 0, d.getWhois())
				.trim();
		String nameServer = valueOfField("Name Server", 0, d.getWhois());

		Calendar cal = Calendar.getInstance();
		SimpleDateFormat dateFormat = new SimpleDateFormat(
				"yyyy-MM-dd hh:mm:ss");
		try {
			cal.setTime(dateFormat.parse(createdDate));
			createdDate = String.format("%02d", cal.get(Calendar.MONTH) + 1)
					+ "/" + String.format("%02d", cal.get(Calendar.DATE)) + "/"
					+ cal.get(Calendar.YEAR);
		} catch (ParseException e) {
		}
		try {
			cal.setTime(dateFormat.parse(expiredDate));
			expiredDate = String.format("%02d", cal.get(Calendar.MONTH) + 1)
					+ "/" + String.format("%02d", cal.get(Calendar.DATE)) + "/"
					+ cal.get(Calendar.YEAR);
		} catch (ParseException e) {
		}

		d.setUpdatedDate(updatedDate);
		d.setExpiredDate(expiredDate);
		d.setCreatedDate(createdDate);
		d.setDomainStatus(domainStatus);
		d.setNameServer(nameServer);
	}

	public static void processWhoisDomain_dot_DEFAULT(Domain d) {
		String whoisDomainResult = ExecCmdHandle.processCommand("whois "
				+ d.getName());
		if (whoisDomainResult != null && whoisDomainResult.length() > 0) {
			d.setWhois(whoisDomainResult);
		}
		String emailString = valueOfField("Tech Email", 0, d.getWhois());
		if (emailString.length() > 0) {
			if (d.getEmail().length() > 0) {
				d.setEmail(d.getEmail() + ", " + emailString);
			} else {
				d.setEmail(emailString);
			}
		}
		String expiredDate = valueOfField("Expiration Date", 1, d.getWhois());
		String createdDate = valueOfField("Creation Date", 1, d.getWhois());
		String updatedDate = valueOfField("Updated Date", 1, d.getWhois());

		Calendar cal = Calendar.getInstance();
		SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MMM-yyyy");
		try {
			cal.setTime(dateFormat.parse(createdDate));
			createdDate = String.format("%02d", cal.get(Calendar.MONTH) + 1)
					+ "/" + String.format("%02d", cal.get(Calendar.DATE)) + "/"
					+ cal.get(Calendar.YEAR);
		} catch (ParseException e) {
		}
		try {
			cal.setTime(dateFormat.parse(expiredDate));
			expiredDate = String.format("%02d", cal.get(Calendar.MONTH) + 1)
					+ "/" + String.format("%02d", cal.get(Calendar.DATE)) + "/"
					+ cal.get(Calendar.YEAR);
		} catch (ParseException e) {
		}
		try {
			cal.setTime(dateFormat.parse(updatedDate));
			updatedDate = String.format("%02d", cal.get(Calendar.MONTH) + 1)
					+ "/" + String.format("%02d", cal.get(Calendar.DATE)) + "/"
					+ cal.get(Calendar.YEAR);
		} catch (ParseException e) {
		}

		d.setUpdatedDate(updatedDate);
		d.setExpiredDate(expiredDate);
		d.setCreatedDate(createdDate);
		d.setNameServer(valueOfField("Name Server", 0, d.getWhois()));
		d.setDomainStatus(valueOfField("Status", 0, d.getWhois()));
	}

	public static void processWhoisIPAddress(Domain d) {
		String whoisIPResult = "";
		String netRange = "";
		boolean existIP = false;

		// Get IPAddress Whois Information
		if (d.getIp().length() > 0) {
			// Check if this ip is beetwen some IPRange,
			Double ipLong = Utils.ipToLong(d.getIp());
			IPRange ipRange = DS_IPRangeModel.checkIPInRange(ipLong);
			if (ipRange != null && ipRange.getWhois().length() > 0) {
				existIP = true;
			}
			if (existIP) {
				whoisIPResult = ipRange.getWhois();
				existIP = true;
			} else {
				whoisIPResult = ExecCmdHandle.processCommand("whois "
						+ d.getIp());
			}
		}

		if (whoisIPResult.length() > 0) {
			netRange = valueOfField("inetnum", 1, whoisIPResult);
			if (netRange.equals("") || netRange.length() == 0) {
				netRange = valueOfField("NetRange", 1, whoisIPResult);
			}
			String orgName = valueOfField("netname", 1, whoisIPResult);
			if (orgName.equals("") || orgName.length() == 0) {
				orgName = valueOfField("OrgName", 1, whoisIPResult);
				d.setWebServerAddress(valueOfField("Address", 0, whoisIPResult));
				d.setWebServerCity(valueOfField("City", 1, whoisIPResult));
			} else {
				String descr = valueOfField("descr", 1, whoisIPResult);
				if (descr.length() > 0) {
					orgName += " - " + descr;
				}
				d.setWebServerAddress(valueOfField("address", 0, whoisIPResult));
				d.setWebServerCountry(valueOfField("country", 1, whoisIPResult));
			}
			d.setWebServerOrgName(orgName);
		}

		// Save IPRange to database
		if (!existIP) {
			IPRange ipRange = new IPRange();
			if (netRange.length() > 0) {
				String minIP = "";
				String maxIP = "";
				String[] tempArray = netRange.split("-");
				if (tempArray != null && tempArray.length == 2) {
					minIP = tempArray[0].trim();
					maxIP = tempArray[1].trim();
				}
				if (minIP.length() > 0 && maxIP.length() > 0) {
					Double min = Utils.ipToLong(minIP);
					Double max = Utils.ipToLong(maxIP);
					if (min != 0 && max != 0) {
						ipRange.setId(netRange.replace(" ", ""));
						ipRange.setMin(min);
						ipRange.setMax(max);
						ipRange.setWhois(whoisIPResult);
						// Save Database
						DS_IPRangeModel.insertDatastore(ipRange);
						JavaCommandLineServiceAccounts.insertIPRange(ipRange); 
					}
				}
			}
		}
	}

	public static String valueOfField(String field, int time, String whois) {
		String value = "";
		p = Pattern.compile(field + ":[^\\n]+[\n]{1}");
		m = p.matcher(whois);
		int count = 0;
		while (m.find()) {
			String match = m.group();
			match = match.replaceAll("\\n|\\r", "").replaceAll("\\s{2,}", " ")
					.replace(field + ":", "").trim();
			if (value.length() > 0) {
				value += ", " + match;
			} else {
				value = match;
			}

			if (time != 0) {
				count += 1;
				if (count == time) {
					break;
				}
			}
		}
		return value;
	}

	public static String valueOfJapaneseWhoisField(String field, int time,
			String whois) {
		String value = "";
		p = Pattern.compile("\\[" + field + "\\][^\\n]+[\n]{1}");
		m = p.matcher(whois);
		int count = 0;
		while (m.find()) {
			String match = m.group();
			match = match.replaceAll("\\n|\\r", "").replaceAll("\\s{2,}", " ")
					.replace("[" + field + "]", "").trim();
			if (value.length() > 0) {
				value += ", " + match;
			} else {
				value = match;
			}

			if (time != 0) {
				count += 1;
				if (count == time) {
					break;
				}
			}
		}
		return value;
	}
}
